<template>
  <div>
    <el-button size="small" @click="$refs.fileInput.click()">选取图片</el-button>
    <input
      ref="fileInput"
      hidden
      type="file"
      :accept="accept.types.toString()"
      @change="fileChange"
    />
    <el-dialog
      title="图片裁剪"
      :visible.sync="cropVisible"
      :close-on-click-modal="false"
      @open="dialogOpen"
    >
      <div class="flex">
        <div class="flex-2">
          <vue-cropper
            ref="cropper"
            :src="imageSrc"
            :view-mode="1"
            :initial-aspect-ratio="1"
            :aspect-ratio="1"
            preview=".preview-box"
          />
          <div class="m-t-10 text-center">
            <el-button-group>
              <el-button type="primary" icon="el-icon-zoom-in" @click="zoom(0.2)" />
              <el-button type="primary" icon="el-icon-zoom-out" @click="zoom(-0.2)" />
            </el-button-group>
            <el-button-group>
              <el-button type="primary" icon="el-icon-refresh-left" @click="rotate(-15)" />
              <el-button type="primary" icon="el-icon-refresh-right" @click="rotate(15)" />
            </el-button-group>
          </div>
        </div>
        <div class="flex-1 m-l-16 flex direction-column align-items-center">
          <div v-if="userId" class="preview-box el-avatar el-avatar--circle s90"></div>
          <div v-else class="preview-box m-t-16 el-avatar el-avatar--square s90"></div>
          <div class="m-t-16 flex content-space-between">
            <el-button type="primary" @click="crop" :loading="isLoading">确定</el-button>
            <el-button @click="cancel">取消</el-button>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { mapState } from 'vuex';
// eslint-disable-next-line import/no-extraneous-dependencies
import 'cropperjs/dist/cropper.css';
import VueCropper from 'vue-cropperjs';

export default {
  name: 'UploadAvatar',
  components: { VueCropper },
  props: {
    accept: { // 允许的类型
      type: Object,
      default: () => ({ types: ['image/jpg', 'image/jpeg', 'image/png'], msg: '仅支持 jpg, jpeg, png 格式的图片类型' }),
    },
    limitSize: { // 单位 Byte，默认2M
      type: Number,
      default: 2097152,
    },
    previewUrl: {
      type: String,
      required: false,
    },
  },
  data() {
    return {
      cropVisible: false, // 图片裁剪区域的可见性
      imageSrc: '', // 选中图片的base64
      isLoading: false,
      filename: '',
    };
  },
  computed: {
    ...mapState(['currentUser']),
    // 大小限制
    limitSizeFixed() {
      let size = this.limitSize;
      if (size < 1024) return `${size}B`;
      size /= 1024;
      if (size < 1024) return `${size}KB`;
      size /= 1024;
      return `${size}MB`;
    },
    userId() { return this.$route.params.userId; },
  },
  methods: {
    // 选中了文件
    fileChange() {
      const file = this.$refs.fileInput.files[0];
      if (!this.accept.types.includes(file.type)) { // 判断选中的文件类型
        this.$message.error(this.accept.msg);
        this.$refs.fileInput.value = '';
      } else if (file.size > this.limitSize) { // 判断选中图片的大小
        this.$message.error(`请选择小于 ${this.limitSizeFixed} 的图片`);
        this.$refs.fileInput.value = '';
      } else {
        this.filename = file.name;
        const fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onload = (e) => {
          this.imageSrc = e.target.result;
          this.cropVisible = true;
          this.$refs.fileInput.value = '';
        };
      }
    },
    // 图片缩放
    zoom(num) { this.$refs.cropper.relativeZoom(num); },
    // 图片旋转
    rotate(deg) { this.$refs.cropper.rotate(deg); },
    // 打开dialog
    dialogOpen() { if (this.$refs.cropper) this.$refs.cropper.replace(this.imageSrc); },
    // 确定裁剪
    async crop() {
      this.isLoading = true;
      const uploadToken = await this.getUploadToken();
      this.$refs.cropper.getCroppedCanvas().toBlob((blob) => {
        const formData = new FormData();
        formData.append('file', blob);
        formData.append('key', `crop-avatar-${new Date().getTime()}/${this.filename}`);
        formData.append('x:user_id', this.currentUser.id);
        formData.append('token', uploadToken);
        this.$api.other.upload(formData)
          .then((res) => {
            this.$emit('avatar', res);
            this.cropVisible = false;
          })
          .catch(() => {})
          .then(() => { this.isLoading = false; });
      });
    },
    // 取消裁剪
    cancel() { this.cropVisible = false; },
    // 获取上传密钥
    getUploadToken() {
      return new Promise((resolve, reject) => {
        this.$api.other.uploadToken()
          .then(res => resolve(res.data.token))
          .catch((err) => {
            this.$message.error('获取上传密钥失败', err);
            this.isLoading = false;
            reject(err);
          });
      });
    },
  },
};
</script>

<style></style>
